'use strict'

process.chdir(__dirname);

const titbit = require('titbit');
const fs = require('fs');
const dbcfg = require('./dbconfig.js');
const pg = require('pg');
const wxkey = require('./wxkey.js');
const {httpcli} = require('gohttp');
const token = require('titbit-token')

try{
    fs.accessSync('./images');
}catch (err){
    fs.mkdirSync('./images');
}

let psql = new pg.Pool(dbcfg)

let cert_path='/usr/local/share';

const app=new titbit({
    //开启调试模式，会输出错误信息
    debug:true,
    globalLog: true,
    cert:`${cert_path}/abc.hiehie.top.pem`,
    key:`${cert_path}/abc.hiehie.top.key`
})

//添加路由
app.get('/', async c => {
    c.send('ok');
})

/**----------------- content路由 ----------------- */

//获取内容列表
app.get('/content', async c => {
    let ret = await psql.query(`select * from content`)

    //等效于 c.res.body = ret.rows
    c.send(ret.rows)
})

//获取具体内容
app.get('/content/:id', async c => {
    let sqltext = `SELECT * FROM content WHERE id=$1`

    let r = await psql.query(sqltext, [c.param.id])

    if(r.rowCount === 0){
        return c.status(404).send('content not found')
    }

    c.send(r.rows[0])
})

//创建内容
app.post('/content', async c => {
    try {
        //提交的Body数据通过c.body获取
        let data = JSON.parse(c.body)
        let sqltext = `INSERT INTO `
            + ` content(id, add_time, detail, title, update_time) `
            + ` VALUES ($1, $2, $3, $4, $5)`
        console.log(data.detail);
        //生成唯一ID
        let id = c.helper.makeId()
        let tm = Date.now()

        let r = await psql.query(sqltext, [
            id, tm, data.detail, data.title, tm
        ])

        if(r.rowCount === 0){
            return c.status(500).send('failed')
        }

        c.send(id)

    } catch (err) {
        c.status(400).send('it is not json data')
    }
})

/**----------------- content路由 - END ----------------- */

app.get('/upload', async c => {
    //c.reply是响应对象，可写的流，
    //在HTTP/1.1中指向reponse，在HTTP/2中指向http2stream
    await c.helper.pipe('./upload.html', c.reply);
})

app.post('/upload', async c => {
    //根据name获取文件对象
    let f = c.getFile('image');

    if(!f){
        return c.status(400).send('image not found');
    }

    //根据传入的原始文件名生成唯一文件名，主要使用f.filename的扩展名
    let fname = c.helper.makeName(f.filename);

    //移动文件到指定位置
    await c.moveFile(f, `./images/${fname}`);

    c.send(fname);

})

//返回图片数据
app.get('/image/:name', async c => {
    //c.param是一个对象，其中的key值是路由参数的名称。
    let imgname = c.param.name
    
    await c.helper.pipe(`./images/${imgname}`, c.reply);

})

let tok = new token({
    //token有效证期，单位为秒
    expires: 45,
    //必须是32位字符
    key: '1a2zm3dfr45tgvbhyu789mkljhbvcdew',

    //必须是16位字符
    iv: 'wgshxhsgwu8kl536'
})

app.get('/mp-login/:code', async c => {
    
    let auth_url = `https://api.weixin.qq.com/sns/jscode2session`
            + `?appid=${wxkey.appid}`
            +`&secret=${wxkey.secret}`
            +`&js_code=${c.param.code}`
            +`&grant_type=authorization_code`

    let ret = await httpcli.get(auth_url)
                            .then(res => {
                                return res.json()
                            })
    c.send(tok.make(ret))
})

app.get('/decrypt/:token', async c => {
    c.send(tok.verify(c.param.token))
})

//运行在8081端口
app.run(8081);


/**
 * HTTP 消息头 content-type 指定了数据的类型（数据的格式）。
 * 
 * Client                              Server
 *  content-type描述的值                 根据content-type的值决定如何解析Body数据。
 *  要和提交的Body数据一致。
 * 
 * content-type：
 * 
 *      multipart/form-data;boundary=xxx  ------  文件解析
 * 
 *      text/*   -------------------------------  文本类型
 *  
 *      application/*  -------------------------  要看具体值，application/json也是文本类型
 *  
 *      ......  --------------------------------  每种类型如何处理是双方设计好的通信方式
 * 
 *      到Web框架这一层面，则如何处理是开发框架设计好的，但通常都要遵循一个原则：
 *          允许开发者做自己的处理。
 * 
 * 在本框架范围内：
 *  multipart类型  c.body是object类型，文件信息解析到c.files
 *  application/x-www-form-urlencoded 传统的表单类型，c.body是object类型，用于获取提交的表单数据。
 *  text/* c.body是文本类型，c.body = c.rawBody.toString('utf8')。
 *  其他类型： c.body 是buffer类型，就是对c.rawBody的引用。
 */